package org.advanced.lua;

import org.advanced.util.ResourceUtil;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.Arrays;

/**
 * @author John.zhang
 * @version Id: LuaTest, v 1.0 2020/12/22 19:52 ZhiYong Exp $
 * 原子级别的命令事务控制
 * <p>
 * 命令
 * eval "return 'HelloWorld'" 0
 * eval "redis.call('set',KEYS[1],ARGV[1])" 1 key1 value1 -> get key1
 * vim gmstu.lua  redis.call('set','key1','value1') return redis.call('get','key1')  -> ./redis-cli --eval gmstu.lua 0
 * <p>
 * 例子1：对IP限流
 * vim ip_limit.lua (参考代码)  ./redis-cli --eval ip_limit.lua app:ip:limit:0.0.0.1 , 5(ARGV[1]) 10(ARGV[2])   (当前ip5秒内只能访问10次)
 * <p>
 * 缓存lua脚本
 * ./redis-cli -> script load "return 'HelloWorld'" -> evalsha "234a3565" 0
 * <p>
 * 例子1：对数值进行乘法
 * script load "local curVal = redis.call("get", KEYS[1]); if curVal == false then curVal = 0 else curVal = tonumber(curVal) end; curVal = curVal * tonumber(ARGV[1]); redis.call("set", KEYS[1],curVal); return curVal" 0
 * set num 2 -> evalsha "234a3565" 6
 * <p>
 * lua死循环脚本处理办法： eval 'while(true) do end' 0 -> SCRIPT KILL
 * lua超时死循环： eval "redis.call('set','key1','value1') while true do end" 0 ->SHUTDOWN NOSAVE
 */
public class LuaTest {
    public static void main(String[] args) {
        Jedis jedis = getJedisUtil();
        jedis.eval("return redis.call('set',KEYS[1],ARGV[1])", 1, "test:lua:key", "John");
        System.out.println(jedis.get("test:lua:key"));
        int max = 10;
        for (int i = 0; i < max; i++) {
            limit();
        }
    }

    /**
     * 10秒内限制访问5次
     */
    public static void limit() {
        Jedis jedis = getJedisUtil();
        // 只在第一次对key设置过期时间
        String lua = "local num = redis.call('incr', KEYS[1])\n" +
                "if tonumber(num) == 1 then\n" +
                "\tredis.call('expire', KEYS[1], ARGV[1])\n" +
                "\treturn 1\n" +
                "elseif tonumber(num) > tonumber(ARGV[2]) then\n" +
                "\treturn 0\n" +
                "else \n" +
                "\treturn 1\n" +
                "end\n";
        Object result = jedis.evalsha(jedis.scriptLoad(lua), Arrays.asList("localhost"), Arrays.asList("10", "5"));
        System.out.println(result);
    }

    private static Jedis getJedisUtil() {
        String ip = ResourceUtil.getKey("redis.host");
        int port = Integer.valueOf(ResourceUtil.getKey("redis.port"));
        String password = ResourceUtil.getKey("redis.password");
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        JedisPool pool = null;
        if (null == password || "".equals(password)) {
            pool = new JedisPool(jedisPoolConfig, ip, port, 10000);
        } else {
            pool = new JedisPool(jedisPoolConfig, ip, port, 10000, password);
        }
        return pool.getResource();
    }
}
